﻿namespace Nomo.UnityCoreModule.UI
{
    /// <summary>
    /// 圆。
    /// </summary>
    public sealed class Circle : UnityEngine.UI.MaskableGraphic, UnityEngine.UI.ILayoutElement
    {
        [UnityEngine.SerializeField]                             private UnityEngine.Texture texture;
        [UnityEngine.SerializeField] [UnityEngine.Range(3, 128)] private int                 segments = 64;

        /// <inheritdoc />
        public override UnityEngine.Texture mainTexture => texture ? texture : material && material.mainTexture ? material.mainTexture : s_WhiteTexture;

        /// <summary>
        /// 纹理。
        /// </summary>
        public UnityEngine.Texture Texture
        {
            get => texture;
            set
            {
                if (texture == value)
                {
                    return;
                }
                texture = value;
                SetVerticesDirty();
                SetMaterialDirty();
            }
        }

        /// <summary>
        /// 边数。
        /// </summary>
        public int Segments
        {
            get => segments;
            set
            {
                if (segments == value)
                {
                    return;
                }
                segments = value;
                SetVerticesDirty();
            }
        }

        /// <inheritdoc />
        public override void SetNativeSize()
        {
            rectTransform.anchorMin = rectTransform.anchorMax = new UnityEngine.Vector2(0.5F, 0.5F);
            var t                                             = mainTexture;
            rectTransform.sizeDelta = new UnityEngine.Vector2(t.width, t.height);
        }

        /// <inheritdoc />
        protected override void OnPopulateMesh(UnityEngine.UI.VertexHelper vh)
        {
            if (segments < 3)
            {
                base.OnPopulateMesh(vh);
                return;
            }

            vh.Clear();

            var verts   = CoreModule.ListPool<UnityEngine.UIVertex>.Get();
            var indices = CoreModule.ListPool<int>.Get();

            var r          = GetPixelAdjustedRect();
            var center     = r.center;
            var halfWidth  = r.width  * 0.5F;
            var halfHeight = r.height * 0.5F;
            var xMin       = r.xMin;
            var xMax       = r.xMax;
            var yMin       = r.yMin;
            var yMax       = r.yMax;

            var uiVertex = UnityEngine.UIVertex.simpleVert;
            uiVertex.color = color;

            uiVertex.position = UnityEngine.Vector2.zero + center;
            uiVertex.uv0      = new UnityEngine.Vector2(UnityEngine.Mathf.InverseLerp(xMin, xMax, uiVertex.position.x), UnityEngine.Mathf.InverseLerp(yMin, yMax, uiVertex.position.y));
            verts.Add(uiVertex);

            var stepAngle = UnityEngine.Mathf.PI * 2F / segments;
            for (var i = 0; i < segments; i++)
            {
                uiVertex.position = new UnityEngine.Vector2(UnityEngine.Mathf.Cos(stepAngle * i) * halfWidth, UnityEngine.Mathf.Sin(stepAngle * i) * halfHeight) + center;
                uiVertex.uv0      = new UnityEngine.Vector2(UnityEngine.Mathf.InverseLerp(xMin, xMax, uiVertex.position.x), UnityEngine.Mathf.InverseLerp(yMin, yMax, uiVertex.position.y));
                verts.Add(uiVertex);
            }

            int index;
            for (index = 1; index < segments; index++)
            {
                indices.Add(0);
                indices.Add(index + 1);
                indices.Add(index);
            }
            indices.Add(0);
            indices.Add(1);
            indices.Add(index);

            vh.AddUIVertexStream(verts, indices);

            CoreModule.ListPool<UnityEngine.UIVertex>.Release(verts);
            CoreModule.ListPool<int>.Release(indices);
        }

        void UnityEngine.UI.ILayoutElement.CalculateLayoutInputHorizontal() { }

        void UnityEngine.UI.ILayoutElement.CalculateLayoutInputVertical() { }

        float UnityEngine.UI.ILayoutElement.minWidth => 0F;

        float UnityEngine.UI.ILayoutElement.minHeight => 0F;

        float UnityEngine.UI.ILayoutElement.preferredWidth => mainTexture.width;

        float UnityEngine.UI.ILayoutElement.preferredHeight => mainTexture.height;

        float UnityEngine.UI.ILayoutElement.flexibleWidth => -1F;

        float UnityEngine.UI.ILayoutElement.flexibleHeight => -1F;

        int UnityEngine.UI.ILayoutElement.layoutPriority => 0;
    }
}
